# coding: utf-8

'''
author: zw
'''
import jwt

from django.core.cache import cache
from django.conf import settings
from django.contrib.auth.models import User

from rest_framework_jwt.settings import api_settings

from rest_framework import exceptions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

CAS_LOGIN_EXPIRE = getattr(settings, 'CAS_LOGIN_EXPIRE', True)
CAS_LOGIN_EXPIRE_TIME = getattr(settings, 'CAS_LOGIN_EXPIRE_TIME', 7200)
CAS_LOGIN_EXPIRE_KEY = getattr(settings, 'CAS_LOGIN_EXPIRE_KEY', 'LOGIN_USER_')


jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER


class ZXAuthentication(JSONWebTokenAuthentication):

    def authenticate_jwt(self, request):
        """
        Returns a two-tuple of payload and token if a valid signature has been
        supplied using JWT-based authentication.  Otherwise returns `None`.
        """
        jwt_value = self.get_jwt_value(request)
        if jwt_value is None:
            return None

        try:
            payload = jwt_decode_handler(jwt_value)
        except jwt.ExpiredSignature:
            msg = ('Signature has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = ('Error decoding signature.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()

        user_info = payload
        user = None
        if not payload.get('customer'):
            user = User.objects.filter(id=payload['user_id']).first()

        return (user or user_info, jwt_value)

    def authenticate(self, request):
        auth_result = self.authenticate_jwt(request)
        if auth_result is None:
            return None

        user_or_user_info, jwt_value = auth_result

        if CAS_LOGIN_EXPIRE:
            key = 'LOGIN_USER_' + str(user_or_user_info.get('user_id') or user_or_user_info.id)

            token = cache.get(key)
            if token is None:
                raise exceptions.AuthenticationFailed(u'Token 过期，请重新登录')

            if token != jwt_value:
                raise exceptions.AuthenticationFailed(u'Token 错误，强制下线')

            cache.set(key, token, CAS_LOGIN_EXPIRE_TIME)
        return (user_or_user_info, jwt_value)
